/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package marketplace_client;

import java.net.InetAddress;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import marketplace_bankserver.BankClient;
import marketplace_bankserver.BankImpl;
import marketplace_server.Item;
import marketplace_server.RejectedException;
import marketplace_server.Server;
import marketplace_server.ServerImpl;
import marketplace_bankserver.Command;
import marketplace_bankserver.CommandName;

/**
 *
 * @author gianmariospacagna
 */
public class ClientImpl extends UnicastRemoteObject implements Client {

    private String username;
    private String password;
    private int requestedPriceRange;
    private boolean registered;
    
    
    public BankClient bankClient;
    private Server server;
    private ClientGUI clientGUI;
    
    private boolean hasBankAccount  = false;
    
    private String serverName   = ServerImpl.class.getSimpleName();
    private String bankName     = BankImpl.class.getSimpleName();
    
    private String serverConnectionString;
    private String bankConnectionString;
    
    private Command command;
    
    public ClientImpl(String id) throws RemoteException {
        super();
        this.username = id;
        try {
            
            // These two variables hold the connection strings to the
            // Server and the Bank
            
            bankConnectionString    = getLookupStringForClasString(bankName);
            serverConnectionString  = getLookupStringForClasString(serverName);
            
             
            // Here we're trying to find the rmi service created by the server 
             
            server = (Server) Naming.lookup(serverConnectionString);
            
            // Create a bankClient to deposit/withdraw funds with
            
            bankClient = new BankClient(bankConnectionString);
            
            clientGUI = new ClientGUI(this);
            clientGUI.setTitle(id);
            clientGUI.setVisible(true);
            
            //register();
            
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        
    }
    
    /*
     *  Getters
     */
    public boolean isRegistered () {
        return registered;
    }
    public void setRegistered (boolean isRegistered) {
        this.registered = isRegistered;
    }
    public int getRequestedPriceRange () {
        return requestedPriceRange;
    }
    public void setRequestedPriceRange (int requestedPriceRange) {
        this.requestedPriceRange = requestedPriceRange;
    }
    public boolean hasBankAccount () {
        return hasBankAccount;
    }
    public Server getServer() {
        return server;
    }
    public BankClient getBankClient() {
        return bankClient;
    }
    public String getLookupStringForClasString(String classString) {        
        try {
            // Gets the IP-address to be used in the RMI Lookup procedure
            String addr = InetAddress.getLocalHost().getHostAddress();
            // Constructs the RMI lookup connection string
            return "rmi://"+addr+":1099/"+classString;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
    public ClientGUI getGUI () {
        return clientGUI;
    }
    /*
     *  Internal methods
     */
    
    public void listItemsOnServer () throws RemoteException {
        System.out.println("ask server to listItemsOnServer");
        getServer().listCurrentlyAvailableItems(this);
    }
    public void publishItemToServer (String name, int price) throws RemoteException {
        //System.out.println("Publishing item to server");
        Item item = new Item(name, price, true, this.username, null);
        
        publishItemToServer(item);
    }
    
    
    public void publishItemToServer (Item item) throws RemoteException {
        System.out.println("Publishing item to server");
        getServer().publishItemOnMarket(this, item);
    }
    public void buyItem (String itemName) throws RemoteException, RejectedException {
        
        
        getServer().buyItem(this, itemName);
    }
    
    public void depositMoney(float amount) throws RemoteException, RejectedException
    {
        if (command == null) 
        {
            command = new Command(CommandName.deposit, username, amount);
        }
        else {
            command.setAmount(amount);
            command.setCommandName(CommandName.deposit);
        }
        
        getBankClient().executeCommand(command);
        
    }
    public void withdrawMoney (float amount) throws  RemoteException, RejectedException {
        if (command == null) 
        {
            command = new Command(CommandName.withdraw, username, amount);
        }
        else {
            command.setAmount(amount);
            command.setCommandName(CommandName.withdraw);
        }
        
        getBankClient().executeCommand(command);
    }
    public void requestPriceRange (int priceRange) throws RemoteException
    {
        //getServer().showInterestForPriceRange(this, priceRange);
    }
    public float getBalance () throws RemoteException, RejectedException {
        try {
            return bankClient.getAccount().getBalance();
        }
        catch (Exception e) {
            return 0.0f;
        }
    }
    
    public void updatePriceOfItemWitName (String itemName,Integer price) throws RemoteException {
        
        Item item = new Item(itemName, price,true, username, null);
        
        getServer().updateItem(this, item);
    }
    /*
     *   CALLBACK METHODS
     */
    
    public void register(String username, String password) throws RemoteException{
        this.username=username;
        this.password=password;
        
        try 
        {
            Client remoteClient = (Client) this;
            server.register(remoteClient,username,password);
            
        } catch (Exception e) 
        {
            e.printStackTrace();
        }
    }

    public void unregister() throws RemoteException {
        server.unregister(this);
    }



    
    
    /*
     *  INTERFACE IMPLEMENTATION
     */
    
    @Override
    public void deposit(float amount) throws RemoteException, RejectedException {
       depositMoney(amount);
    }

    @Override
    public void withdraw(float amount) throws RemoteException, RejectedException {
        withdrawMoney(amount);
    }
    
    public void createBankAccount () throws RemoteException {
        if (hasBankAccount) {return;}
        
        Command c = new Command(CommandName.newAccount, username, 1000.0f);
        try {
            
            bankClient.executeCommand(c);
            hasBankAccount = true;
            
        } catch (RejectedException ex) {
            Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    
    @Override
    public String getID() {
        return username;
    }

    @Override
    public void serverHasItemInMyPriceRange(ArrayList<Item> items) throws RemoteException {
        getGUI().notifyUserOfItemInPriceRange(items);
    }

    @Override
    public void serverHasItemsAvailable(ArrayList<Item> items) throws RemoteException {
        getGUI().refreshTableWithItems(items);
    }

    public void transactionFailedWithException(String exceptionMessage) throws RemoteException {
        getGUI().notifyUserOfTransactionStatus(exceptionMessage);
    }

    public void itemHasBeenSold(Item item) throws RemoteException {
       getGUI().notifyUserOfItemStatus(item);
    }
    public void updateBalance() throws RemoteException {
        try {
            getGUI().updateBalance();
        } catch (RejectedException ex) {
            Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    void login(String usr, String pwd) throws RemoteException
    {
        getServer().logIn(this, username, password);
    }
    
    
    
}
